import random

from pygame import Surface
from pygame.font import Font
from pygame.rect import RectType

from game.LevelManager import Level, Block
from game.TextureManager import Texture, TextureA, TextureGifs
from util import Logger as log
import pygame
from game import TextureManager as rm

screen: Surface | None = None


class Config:
    scale = 2


config: Config = Config()
config_warehouse = []


def init(value):
    global screen
    log.info("RenderManager -> init")
    screen = value
    pygame.font.init()


def config_push():
    config_warehouse.append(config)


def config_pop():
    global config
    config = config_warehouse.pop()


gifs_cache: dict = {"count": 0}


def get_texture(type: str, texture_name: str) -> Texture:
    return rm.textures[type][texture_name]


def draw(type: str, texture_name: str, x: int, y: int, enable_xy_scale=True, enable_animation=True,
         animation_homing=False, scale=config.scale, on_screen=screen):
    if on_screen is None:
        on_screen = screen

    texture: Texture = get_texture(type, texture_name)

    if enable_xy_scale:
        x = x * 16 * scale
        y = y * 16 * scale

    if isinstance(texture, TextureA):
        image = rm.textures[type]["image"].get_image(scale)
        on_screen.blit(image, (x, y), texture.get_rect(scale))

    elif isinstance(texture, TextureGifs):
        list = texture.textures

        if not gifs_cache["count"] in gifs_cache:
            gifs_cache[gifs_cache["count"]] = random.randint(0, len(list) * texture.interval - 1)
        elif gifs_cache[gifs_cache["count"]] >= len(list) * texture.interval:
            gifs_cache[gifs_cache["count"]] = 0

        draw(type, texture.textures[int(gifs_cache[gifs_cache["count"]] / texture.interval)], x, y, False,
             enable_animation=enable_animation, scale=scale,on_screen=on_screen)

        if enable_animation:
            gifs_cache[gifs_cache["count"]] += 1
        if animation_homing:
            gifs_cache[gifs_cache["count"]] = 0

        gifs_cache["count"] += 1


def get_size(type: str, texture_name: str):
    return rm.textures[type][texture_name].get_rect().width, rm.textures[type][texture_name].get_rect().height


def reload_gifs_cache():
    gifs_cache.clear()
    gifs_cache["count"] = 0


def update_gifs_cache():
    gifs_cache["count"] = 0


def update_cache():
    update_gifs_cache()


font_cache: [int, Font] = {}


def draw_string(text: str, x: int, y: int, color: tuple[int, int, int] | str | int, size: int, on_screen=screen):
    if on_screen is None:
        on_screen = screen
    try:
        s = font_cache[size].render(text, False, color)
        r: RectType = s.get_rect()
        r.x = x
        r.y = y
        on_screen.blit(s, r)
    except KeyError:
        font_cache[size] = pygame.font.Font("./resources/font/font.ttf", size)
        s = font_cache[size].render(text, False, color)
        r: RectType = s.get_rect()
        r.x = x
        r.y = y
        on_screen.blit(s, r)


def get_string_size(text: str, size: int) -> tuple[int, int]:
    try:
        return font_cache[size].render(text, False, "red").get_rect().width, font_cache[size].render(text, False,
                                                                                                     "red").get_rect().height
    except KeyError:
        font_cache[size] = pygame.font.Font("./resources/font/font.ttf", size)
        return font_cache[size].render(text, False, "red").get_rect().width, font_cache[size].render(text, False,
                                                                                                     "red").get_rect().height


def get_screen_size() -> tuple[int, int]:
    return screen.get_size()


def draw_boxes(x: int, y: int, x2: int, y2: int):
    temp_y = y
    while x <= x2:
        while y <= y2:
            draw("overworld", "box", x, y)
            y += 1
        x += 1
        y = temp_y


def draw_level(level: Level, scale=config.scale, x=0, y=0, enable_draw_player=True, on_screen=None):
    if on_screen is None:
        on_screen = screen
    for key in sorted(level.blocks.keys()):
        blocks: list[Block] = level.blocks[key]
        for block in blocks:
            if not block.texture == "none":
                if block.type == "player" and enable_draw_player:
                    draw_player(level.player.x * 16 * scale + x, level.player.y * 16 * scale + y,
                                level.player.direction, level.player.move, enable_xy_scale=False, scale=scale,on_screen=on_screen)
                else:
                    draw(block.texture[0], block.texture[1], block.x * 16 * scale + x, block.y * 16 * scale + y,
                         enable_xy_scale=False, scale=scale,on_screen=on_screen)


def draw_player(x: int, y: int, direction: int, move=False, scale=config.scale, enable_xy_scale=True, on_screen=screen):
    if on_screen is None:
        on_screen = screen
    if enable_xy_scale:
        x = x * 16 * scale
        y = y * 16 * scale
    type = "player"
    texture_name = f"player_walk_{direction}"
    draw(type, texture_name, x, y, False, move, not move, scale=scale,on_screen=on_screen)
